#pragma once
#ifndef SMPPSESSION_HPP
#define SMPPSESSION_HPP

#include "SMPPEncoder.hpp"
#include "SMPPDecoder.hpp"
#include "SMPPValidator.hpp"
#include <QSslSocket>
#include <QNetworkProxy>
#include <QSslConfiguration>
#include <QTimerEvent>

using namespace smpp::encoder;
using namespace smpp::decoder;
using namespace smpp::validator;

namespace smpp{
namespace session{

class SMPP_DLLPRFX Request: public QObject{
	Q_OBJECT
public:
	Request(const Bind &,int);

	Request(const Unbind &,int);

	Request(const EnquireLink &,int);

	Request(const SubmitSM &,int);

	Request(const DataSM &,int);

	Request(const SubmitMulti &,int);

	Request(const DeliverSM &,int);

	Request(const BroadcastSM &,int);

	Request(const CancelSM &,int);

	Request(const QuerySM &,int);

	Request(const ReplaceSM &,int);

	Request(const QueryBroadcastSM &,int);

	Request(const CancelBroadcastSM &,int);

	Request(const Request &);

	~Request();

	bool operator ==(const Header &) const;

protected:

	void timerEvent(QTimerEvent *);

private:

	void *_Request;

signals:

	void onBindTransmitterTimeout(const Bind &);

	void onBindReceiverTimeout(const Bind &);

	void onBindTransceiverTimeout(const Bind &);

	void onUnbindTimeout(const Unbind &);

	void onEnquireLinkTimeout(const EnquireLink &);

	void onSubmitSMTimeout(const SubmitSM &);

	void onDataSMTimeout(const DataSM &);

	void onSubmitMultiTimeout(const SubmitMulti &);

	void onDeliverSMTimeout(const DeliverSM &);

	void onBroadcastSMTimeout(const BroadcastSM &);

	void onCancelSMTimeout(const CancelSM &);

	void onQuerySMTimeout(const QuerySM &);

	void onReplaceSMTimeout(const ReplaceSM &);

	void onQueryBroadcastSMTimeout(const QueryBroadcastSM &);

	void onCancelBroadcastSMTimeout(const CancelBroadcastSM &);

};

class SMPP_DLLPRFX Session: public QObject{
	Q_OBJECT
public:
	enum State{
		Open,
		Bound_TX,
		Bound_RX,
		Bound_TRX,
		Unbound,
		Closed,
		Outbound
	};

	Session(int sessionInitTime,int enquireLinkTime,int inactivityTime,
		int responseTime,const QHostAddress &host,quint16 port);

	void setSocketDescriptor(int);

signals:

	void onOpen();

	void onClose();

	void onBind(const Bind &);

	void onBindResp(const BindResp &);

	void onUnbind(const Unbind &);

	void onOutbind(const Outbind &);

	void onUnbindResp(const UnbindResp &);

	void onEnquireLink(const EnquireLink &);

	void onEnquireLinkResp(const EnquireLinkResp &);

	void onAlertNotification(const AlertNotification &);

	void onGenericNack(const GenericNack &);

	void onSubmitSM(const SubmitSM &);

	void onSubmitSMResp(const SubmitSMResp &);

	void onDataSM(const DataSM &);

	void onDataSMResp(const DataSMResp &);

	void onSubmitMulti(const SubmitMulti &);

	void onSubmitMultiResp(const SubmitMultiResp &);

	void onDeliverSM(const DeliverSM &);

	void onDeliverSMResp(const DeliverSMResp &);

	void onBroadcastSM(const BroadcastSM &);

	void onBroadcastSMResp(const BroadcastSMResp &);

	void onCancelSM(const CancelSM &);

	void onCancelSMResp(const CancelSMResp &);

	void onQuerySM(const QuerySM &);

	void onQuerySMResp(const QuerySMResp &);

	void onReplaceSM(const ReplaceSM &);

	void onReplaceSMResp(const ReplaceSMResp &);

	void onQueryBroadcastSM(const QueryBroadcastSM &);

	void onQueryBroadcastSMResp(const QueryBroadcastSMResp &);

	void onCancelBroadcastSM(const CancelBroadcastSM &);

	void onCancelBroadcastSMResp(const CancelBroadcastSMResp &);

	void onBindTimeout(const Bind &);

	void onUnbindTimeout(const Unbind &);

	void onEnquireLinkTimeout(const EnquireLink &);

	void onSubmitSMTimeout(const SubmitSM &);

	void onDataSMTimeout(const DataSM &);

	void onSubmitMultiTimeout(const SubmitMulti &);

	void onDeliverSMTimeout(const DeliverSM &);

	void onBroadcastSMTimeout(const BroadcastSM &);

	void onCancelSMTimeout(const CancelSM &);

	void onQuerySMTimeout(const QuerySM &);

	void onReplaceSMTimeout(const ReplaceSM &);

	void onQueryBroadcastSMTimeout(const QueryBroadcastSM &);

	void onCancelBroadcastSMTimeout(const CancelBroadcastSM &);

	void onStateChanged();

	void onSocketError(QAbstractSocket::SocketError);

	void onPduError(quint32,const Header &);

	void onSessionInitTimerTimeout();

	void onEnquireLinkTimerTimeout();

	void onInactivityTimerTimeout();

public slots:

	void _Open();

	void _Close();

	void _Bind(const Bind &);

	void _BindResp(const BindResp &);

	void _Outbind(const Outbind &);

	void _Unbind(const Unbind &);

	void _UnbindResp(const UnbindResp &);

	void _EnquireLink(const EnquireLink &);

	void _EnquireLinkResp(const EnquireLinkResp &);

	void _AlertNotification(const AlertNotification &);

	void _GenericNack(const GenericNack &);

	void _SubmitSM(const SubmitSM &);

	void _SubmitSMResp(const SubmitSMResp &);

	void _DataSM(const DataSM &);

	void _DataSMResp(const DataSMResp &);

	void _SubmitMulti(const SubmitMulti &);

	void _SubmitMultiResp(const SubmitMultiResp &);

	void _DeliverSM(const DeliverSM &);

	void _DeliverSMResp(const DeliverSMResp &);

	void _BroadcastSM(const BroadcastSM &);

	void _BroadcastSMResp(const BroadcastSMResp &);

	void _CancelSM(const CancelSM &);

	void _CancelSMResp(const CancelSMResp &);

	void _QuerySM(const QuerySM &);

	void _QuerySMResp(const QuerySMResp &);

	void _ReplaceSM(const ReplaceSM &);

	void _ReplaceSMResp(const ReplaceSMResp &);

	void _QueryBroadcastSM(const QueryBroadcastSM &);

	void _QueryBroadcastSMResp(const QueryBroadcastSMResp &);

	void _CancelBroadcastSM(const CancelBroadcastSM &);

	void _CancelBroadcastSMResp(const CancelBroadcastSMResp &);

protected:

	void timerEvent(QTimerEvent *);

private:

	State _State;

	Encoder _Encoder;

	Decoder _Decoder;

	Validator _Validator;

	QSslSocket _Socket;

	bool _UseSsl;

	bool _UseProxy;

	QHostAddress _Host;

	quint16 _Port;

	QAtomicInt _UseEncoder;

	QAtomicInt _UseDecoder;

	QAtomicInt _UseRequestList;

	int _SessionInitTimerId;

	int _EnquireLinkTimerId;

	int _InactivityTimerId;
	
	int _SessionInitTime;

	int _EnquireLinkTime;

	int _InactivityTime;

	int _ResponseTime;

	QList<Request *> _RequestList;

	void _SendPdu();

	void _AddRequest(Request *);

	bool _DelRequest(const Header &);

	void _SetState(const State);

private slots:

	void _OpenResp();

	void _CloseResp();

	void _DecodePdu();

	void _RequestTimeout(const Bind &);

	void _RequestTimeout(const Unbind &);

	void _RequestTimeout(const EnquireLink &);

	void _RequestTimeout(const SubmitSM &);

	void _RequestTimeout(const DataSM &);

	void _RequestTimeout(const SubmitMulti &);

	void _RequestTimeout(const DeliverSM &);

	void _RequestTimeout(const BroadcastSM &);

	void _RequestTimeout(const CancelSM &);

	void _RequestTimeout(const QuerySM &);

	void _RequestTimeout(const ReplaceSM &);

	void _RequestTimeout(const QueryBroadcastSM &);

	void _RequestTimeout(const CancelBroadcastSM &);

	void _SocketError(QAbstractSocket::SocketError);

};

}
}

#endif
